package top.wilsonlv.jaguar.cloud.auth.extension.device;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StringUtils;
import top.wilsonlv.jaguar.cloud.auth.sdk.token.DeviceAuthenticationToken;
import top.wilsonlv.jaguar.cloud.auth.security.LoginFailureHandler;
import top.wilsonlv.jaguar.cloud.auth.security.LoginSuccessHandler;
import top.wilsonlv.jaguar.oauth2.security.Oauth2SecurityConstant;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import static top.wilsonlv.jaguar.cloud.auth.extension.OAuth2ExtensionContant.*;

/**
 * @author lvws
 * @since 2022/1/6
 */
@Slf4j
public class DeviceAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public static final String DEVICE_LOGIN_PATH = "/login/device";


    public DeviceAuthenticationFilter(AuthenticationManager authenticationManager,
                                      LoginSuccessHandler loginSuccessHandler, LoginFailureHandler loginFailureHandler) {
        super(new AntPathRequestMatcher(DEVICE_LOGIN_PATH, HttpMethod.POST.name()), authenticationManager);

        setAuthenticationSuccessHandler(loginSuccessHandler);
        setAuthenticationFailureHandler(loginFailureHandler);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!request.getMethod().equals(HttpMethod.POST.name())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String userIdStr = request.getParameter(QUERY_PARAMETER_USER_ID_KEY);
        if (!StringUtils.hasText(userIdStr)) {
            throw new BadCredentialsException("用户ID为非空");
        }
        long userId = Long.parseLong(userIdStr);

        String deviceAuthType = request.getParameter(QUERY_PARAMETER_DEVICE_AUTH_TYPE_KEY);
        if (!StringUtils.hasText(deviceAuthType)) {
            throw new BadCredentialsException("设备授权方式为非空");
        }

        String deviceUid = request.getParameter(QUERY_PARAMETER_DEVICE_UID_KEY);
        if (!StringUtils.hasText(deviceUid)) {
            throw new BadCredentialsException("设备UID为非空");
        }

        String timestampStr = request.getParameter(Oauth2SecurityConstant.PARAMETER_TIMESTAMP);
        long timestamp;
        if (!StringUtils.hasText(timestampStr)) {
            throw new BadCredentialsException("时间戳为非空");
        } else {
            timestamp = Long.parseLong(timestampStr);
        }

        String nonce = request.getParameter(Oauth2SecurityConstant.PARAMETER_NONCE);
        if (!StringUtils.hasText(nonce)) {
            throw new BadCredentialsException("随机数为非空");
        }

        String sign = request.getParameter(Oauth2SecurityConstant.PARAMETER_SIGN);
        if (!StringUtils.hasText(sign)) {
            throw new BadCredentialsException("签名为非空");
        }

        DeviceAuthenticationToken authRequest = new DeviceAuthenticationToken(userId,
                deviceUid, deviceAuthType, timestamp, nonce, sign, request.getParameterMap());
        // Allow subclasses to set the "details" property
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(authRequest);
    }

}
